package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.utils;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.FileHandleTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ResponseResult;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FileUploadLogVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowModelFileResourceHandleVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FileUploadLogRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.common.OssProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.flowable.engine.common.impl.cfg.IdGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

/**
　　* @description: 文件资源管理工具类
　　* @author shenrm
　　* @date 2021/11/23 13:29
　　*/
@Slf4j
@Component
public class FileResourceManageUtil {

    @Autowired
    private OssProperties ossProperties;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private FileUploadLogRepository fileUploadLogRepository;

    /**
     * OSS的文件存储目录,流程文件目录
     */
    private static String FLOWFOLDER = "flow";

    /**
     * OSS的文件存储目录,流程模型节点文件目录
     */
    private static String ACTIVITYFOLDER = "activity";

    /**
     * 文件分隔符
     */
    private static String FILESPLIT = "|";

    /**
     * 文件分隔符
     */
    private static String KEYSPLIT = "\\|";

    /**
     * 文件路径分隔符
     */
    private static String FILEPATHSPLIT = "/";

    /**
     * 展示文件最大数量
     */
    private static int FILEMAXCOUNT = 200;

    /**
     * 文件上传
     *
     * @param fileList
     * @param requestVo
     * @return
     */
    public ResponseResult fileUpload(List<MultipartFile> fileList, FlowModelFileResourceHandleVo requestVo) {
        // 设置oss
        ResponseResult responseResult = this.setOssProperties();
        if(!responseResult.isSuccess()) {
            return responseResult;
        }
        // 文件上传
        String fileName = null;
        String url = null;
        // 生成唯一的附件ID
        String attachId = "";
        try {
            // 获取文件存储地址
            String filePath = this.getFilePath(requestVo);

            // 获取oss client
            OSSClient ossClient = null;
            try {
                ossClient = OssUtil.getOSSClient();
            } catch (Exception e) {
                log.error(ErrorCode.CREATE_OSS_CLIENT_FAIL.errMessage(), e.getMessage(), e);
                return ResponseResult.fail(ErrorCode.CREATE_OSS_CLIENT_FAIL.errCode(), ErrorCode.CREATE_OSS_CLIENT_FAIL.errMessage());
            }
            if(Objects.isNull(ossClient)) {
                return ResponseResult.fail(ErrorCode.GET_OSS_CLIENT_NOT_EXIST.errCode(), ErrorCode.GET_OSS_CLIENT_NOT_EXIST.errMessage());
            }

            // 循环处理文件上传
            for (int i = 0; i < fileList.size(); i++) {
                // 获取附件对象
                MultipartFile file = fileList.get(i);

                // 获取上传的文件名称,例如:test.docx
                String originalFilename = file.getOriginalFilename();
                if (!file.isEmpty()) {
                    byte[] bytes = file.getBytes();
                    // 生成唯一的附件ID
                    attachId = idGenerator.getNextId();
                    // 拼接文件名
                    String fName= attachId + FILESPLIT + originalFilename;
                    // 拼接文件下载地址
                    String ossFileName = filePath + FILEPATHSPLIT + fName;
                    fileName = OssUtil.uploadBytes(bytes, originalFilename, ossFileName, ossClient);
                }
            }
            url = OssUtil.getUrl(fileName);
        } catch (Exception exception) {
            log.error("文件上传失败,失败原因:", exception.getMessage(), exception);
            return ResponseResult.fail(ErrorCode.FILE_RESOURCE_UPLOAD_FAIL.errCode(), ErrorCode.FILE_RESOURCE_UPLOAD_FAIL.errMessage());
        }

        // 插入文件上传操作日志表
        try {
            this.insertUploadLog(attachId, fileName, url);
        }catch (Exception ex) {
            log.error("文件上传插入操作日志失败,失败原因:" + ex.getMessage(), ex);
        }
        return ResponseResult.success(attachId);
    }


    /**
     * 文件下载
     *
     * @param requestVo
     * @return
     */
    public ResponseResult downLoadFile(FlowModelFileResourceHandleVo requestVo) {
        // 设置oss
        ResponseResult responseResult = this.setOssProperties();
        if(!responseResult.isSuccess()) {
            return responseResult;
        }

        // 文件路径
        String filePath = this.getFilePath(requestVo);

        // 获取oss client
        OSSClient ossClient = null;
        try {
            ossClient = OssUtil.getOSSClient();
        } catch (Exception e) {
            log.error(ErrorCode.CREATE_OSS_CLIENT_FAIL.errMessage(), e.getMessage(), e);
            return ResponseResult.fail(ErrorCode.CREATE_OSS_CLIENT_FAIL.errCode(), ErrorCode.CREATE_OSS_CLIENT_FAIL.errMessage());
        }
        if(Objects.isNull(ossClient)) {
            return ResponseResult.fail(ErrorCode.GET_OSS_CLIENT_NOT_EXIST.errCode(), ErrorCode.GET_OSS_CLIENT_NOT_EXIST.errMessage());
        }

        // 下载文件地址
        String attachPath = filePath + FILEPATHSPLIT + requestVo.getAttachId() + FILESPLIT + requestVo.getFileName();

        // 获取文件
        OSSObject ossObject = null;
        try {
            ossObject = ossClient.getObject(ossProperties.getBucketName(), attachPath);
        } catch (Exception e) {
            log.error(ErrorCode.GET_OSS_FILE_FAIL.errMessage(), e.getMessage());
            return ResponseResult.fail(ErrorCode.GET_OSS_FILE_FAIL.errCode(), ErrorCode.GET_OSS_FILE_FAIL.errMessage());
        }

        // 文件下载
        try {
            // 输出文件流
            OssUtil.downloadFileByFilePath(ossObject, requestVo.getFileName());
        } catch(Exception ex) {
            log.error("文件下载失败,失败原因：", ex.getMessage(), ex);
            return ResponseResult.fail(ErrorCode.FILE_RESOURCE_DOWN_LOAD_FAIL.errCode(), ErrorCode.FILE_RESOURCE_DOWN_LOAD_FAIL.errMessage());
        }
        return ResponseResult.success("文件下载成功");
    }

    /**
     * 删除文件
     *
     * @param requestVo
     * @return
     */
    public ResponseResult deleteFile(FlowModelFileResourceHandleVo requestVo) {
        // 设置oss
        ResponseResult responseResult = this.setOssProperties();
        if(!responseResult.isSuccess()) {
            return responseResult;
        }

        // 拼接文件路径
        String filePath = this.getFilePath(requestVo) + FILEPATHSPLIT + requestVo.getAttachId() + FILESPLIT + requestVo.getFileName();

        // 获取oss client
        OSSClient ossClient = null;
        try {
            ossClient = OssUtil.getOSSClient();
        } catch (Exception e) {
            log.error(ErrorCode.CREATE_OSS_CLIENT_FAIL.errMessage(), e);
            return ResponseResult.fail(ErrorCode.CREATE_OSS_CLIENT_FAIL.errCode(), ErrorCode.CREATE_OSS_CLIENT_FAIL.errMessage());
        }
        if(Objects.isNull(ossClient)) {
            return ResponseResult.fail(ErrorCode.GET_OSS_CLIENT_NOT_EXIST.errCode(), ErrorCode.GET_OSS_CLIENT_NOT_EXIST.errMessage());
        }
        try {
            ossClient.deleteObject(ossProperties.getBucketName(), filePath);
        } catch (Exception e) {
            log.error("文件删除失败,失败原因：", e.getMessage(), e);
            return ResponseResult.fail(ErrorCode.FILE_RESOURCE_DELETE_FAIL.errCode(),ErrorCode.FILE_RESOURCE_DELETE_FAIL.errMessage());
        }
        return ResponseResult.success("文件删除成功");
    }

    /**
     *
     * @param requestVo
     * @return
     */
    public ResponseResult getFileList(FlowModelFileResourceHandleVo requestVo) {
        // 设置oss
        ResponseResult responseResult = this.setOssProperties();
        if(!responseResult.isSuccess()) {
            return responseResult;
        }

        // 获取oss client
        OSSClient ossClient = null;
        try {
            ossClient = OssUtil.getOSSClient();
        } catch (Exception e) {
            log.error(ErrorCode.CREATE_OSS_CLIENT_FAIL.errMessage(), e);
            return ResponseResult.fail(ErrorCode.CREATE_OSS_CLIENT_FAIL.errCode(), ErrorCode.CREATE_OSS_CLIENT_FAIL.errMessage());
        }

        if(Objects.isNull(ossClient)) {
            return ResponseResult.fail(ErrorCode.GET_OSS_CLIENT_NOT_EXIST.errCode(), ErrorCode.GET_OSS_CLIENT_NOT_EXIST.errMessage());
        }
        // 获取文件列表
        ObjectListing objectList = null;
        try {
            objectList = ossClient.listObjects(ossProperties.getBucketName(), this.getFilePath(requestVo));
        } catch (Exception e) {
            log.error(ErrorCode.GET_OSS_FILE_FAIL.errMessage(), e);
            return ResponseResult.fail(ErrorCode.GET_OSS_FILE_FAIL.errCode(), ErrorCode.GET_OSS_FILE_FAIL.errMessage());
        }
        // 获取oss object对象汇总信息
        List<OSSObjectSummary> objectSummaries = objectList.getObjectSummaries();
        if(CollectionUtils.isEmpty(objectSummaries)) {
            return ResponseResult.success(Collections.emptyList());
        }
        List<FlowModelFileResourceHandleVo> fileList = new ArrayList<>();
        for(OSSObjectSummary summary:objectSummaries) {
            fileList.addAll(this.convertKeyToFileList(summary.getKey()));
        }
        return ResponseResult.success(fileList);
    }

    /**
     * 转换成文件数据列表
     *
     * @param key
     * @return
     */
    public List<FlowModelFileResourceHandleVo> convertKeyToFileList(String key) {
        List<FlowModelFileResourceHandleVo> voList = new ArrayList<>();
        String[] fileNameArr = key.split(KEYSPLIT);
        if(fileNameArr != null && fileNameArr.length == 2) {
            FlowModelFileResourceHandleVo vo = new FlowModelFileResourceHandleVo();
            // 附件ID
            vo.setAttachId(fileNameArr[0].substring(fileNameArr[0].lastIndexOf(FILEPATHSPLIT)+1));
            // 附件名称
            vo.setFileName(fileNameArr[1]);
            voList.add(vo);
        }
        return voList;
    }

    /**
     * 插入文件上传日志
     *
     * @param attachId
     * @param fileName
     * @param url
     */
    public void insertUploadLog(String attachId, String fileName, String url) {
        FileUploadLogVo fileUploadLog = new FileUploadLogVo();
        fileUploadLog.setId(attachId);
        fileUploadLog.setFileName(fileName);
        fileUploadLog.setCreateTime(new Date());
        fileUploadLog.setUpdateTime(new Date());
        fileUploadLog.setUrl(url);
        fileUploadLogRepository.insertFileUploadLog(fileUploadLog);
    }

    /**
     * 获取文件上传或下载路径
     *
     * @return
     */
    private String getFilePath(FlowModelFileResourceHandleVo requestVo) {
        if(Objects.isNull(requestVo)) {
            return "";
        }

        // 业务类型
        String serviceType = requestVo.getServiceType();

        // 拼接组装下载文件的路径,根目录,拼接流程模型id和节点编码
        String filePath = "";
        if(Objects.equals(serviceType, FileHandleTypeEnum.FLOWACTIVITYMODEL.getCode())) {
            filePath = FLOWFOLDER + FILEPATHSPLIT + ACTIVITYFOLDER;
        } else {
            filePath = FLOWFOLDER;
        }
        return filePath;
    }

    /**
     * oss server设置属性
     */
    private ResponseResult setOssProperties() {
        try {
            OssUtil.setup(ossProperties.getEndpoint(), ossProperties.getAccessKey(), ossProperties.getSecretKey(), ossProperties.getBucketName());
        } catch (Exception e) {
            log.error(ErrorCode.SET_OSS_PROPERTIES_FAIL.errMessage(), e.getMessage(), e);
            return ResponseResult.fail(ErrorCode.SET_OSS_PROPERTIES_FAIL.errCode(), ErrorCode.SET_OSS_PROPERTIES_FAIL.errMessage());
        }
        return ResponseResult.success();
    }

}
